/**
 * TODO: Create Acceptable and Ignoring Preconditions Manager, TaskManager, PreconditionsTask 
 */

package gugga.tasks
{
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.tasks.events.TaskEvent;
	import gugga.tasks.helpers.IPreconditionsManager;
	import gugga.tasks.helpers.PreconditionsManager;
	import gugga.tasks.helpers.PreconditionsManagerEvent;
	import gugga.utils.DoLaterUtil;

	[Event(name="start", type="TaskEvent")]
	[Event(name="interrupted", type="TaskEvent")]
	[Event(name="completed", type="TaskEvent")]
	[Event(name="preconditionsMet", type="PreconditionsManagerEvent")]
	
	/**
	 * <code>PreconditionsTask</code> class is simply a task-wrapper for 
	 * <code>IPreconditionsManager</code> objects. <code>PreconditionsTask</code> 
	 * is initialized with an already existing <code>IPreconditionsManager</code> 
	 * object through the <code>PreconditionsTask</code> constructor. This 
	 * <code>IPreconditionsManager</code> object can already containt several 
	 * preconditions, or these preconditions could be added through the wrapped 
	 * functionallity of the <code>IPreconditionsManager</code> object. 
	 * <p>
	 * <code>PreconditionsTask</code> will fire event <b><i>completed</i></b> only if: 
	 * <ul>
	 * 	<li><code>PreconditionsTask</code> is started with its <code>start()</code> method</li>
	 * 	<li><code>PreconditionsTask</code> is not interrupted with its <code>interrupt()</code> method</li>
	 * 	<li>all preconditions are met</li>
	 * </ul>
	 * <p>
	 * <b>IMPORTANT NOTICE!!!</b>
	 * Future version of <code>PreconditionsTask</code> should reconsider the need 
	 * for implementing the <code>IPreconditionsManager</code> interface. The 
	 * <code>IPreconditionsManager</code> wrapped object could be exposed through 
	 * <code>public</code> property. This way all managing responsibilities will be 
	 * delegated to the <code>IPreconditionsManager</code> object, and its 
	 * functionallity will be no longer wrapped up in 
	 * <code>PreconditionsTask</code>.
	 * 
	 * @author Barni
	 * @see gugga.tasks.helpers.IPreconditionsManager
	 * @see gugga.tasks.helpers.PreconditionsManager
	 */	
	public class PreconditionsTask extends EventDispatcher implements IPreconditionsManager, ITask
	{
		private var mWrappedManager : IPreconditionsManager;
		private var mIsRunning : Boolean;
		private var mResetBeforeStart : Boolean;
		
		public function get PreconditionsMet() : Boolean
		{
			return getPreconditionsMet();
		}
		
		public function get Accepting() : Boolean
		{
			return isAccepting();
		}
		
		public function PreconditionsTask(aWrappedManager : IPreconditionsManager = null)
		{
			mIsRunning = false;
			mResetBeforeStart = false;
			
			if(aWrappedManager)
			{
				mWrappedManager = aWrappedManager;
			}
			else if(!mWrappedManager)
			{
				mWrappedManager = new PreconditionsManager();
			}
			
			mWrappedManager.addEventListener(
				PreconditionsManagerEvent.PRECONDITIONS_MET,
				onPreconditionsMet);
		}
	
		public function start() : void 
		{
			mIsRunning = true;
			if(mResetBeforeStart)
			{
				reset();
			}
	
			dispatchEvent(new TaskEvent(TaskEvent.START));
			
			if(PreconditionsMet)
			{
				mIsRunning = false;
				var eventObject : TaskEvent = new TaskEvent(TaskEvent.COMPLETED);
				DoLaterUtil.doLater(dispatchEvent, [eventObject], 1);
			}
		}
	
		public function isRunning() : Boolean 
		{
			return mIsRunning;
		}
		
		public function isImmediatelyInterruptable() : Boolean 
		{
			return true;
		}
	
		public function interrupt() : void 
		{
			mIsRunning = false;
			mResetBeforeStart = true;
			/**
			 * This will change Accepting of the manager to false
			 */
			ignoreAll();
			dispatchEvent(new TaskEvent(TaskEvent.INTERRUPTED));
		}
	
		public function isAccepting() : Boolean 
		{
			return mWrappedManager.isAccepting();
		}
	
		public function getPreconditionsMet() : Boolean 
		{
			return mWrappedManager.getPreconditionsMet();
		}
	
		public function add(aPrecondition : EventDescriptor) : void 
		{
			mWrappedManager.add(aPrecondition);
		}
	
		public function remove(aPrecondition : EventDescriptor) : void 
		{
			mWrappedManager.remove(aPrecondition);
		}
	
		public function removeByEventSource(aEventSource : IEventDispatcher) : void 
		{
			mWrappedManager.removeByEventSource(aEventSource);
		}
	
		public function replace(
			aPrecondition : EventDescriptor, 
			aNewPrecondition : EventDescriptor) : void 
		{
			mWrappedManager.replace(aPrecondition, aNewPrecondition);
		}
	
		public function replaceEventSource(
			aEventSource : IEventDispatcher, 
			aNewEventSource : IEventDispatcher) : void 
		{
			mWrappedManager.replaceEventSource(aEventSource, aNewEventSource);
		}
	
		public function contains(aPrecondition : EventDescriptor) : Boolean 
		{
			return mWrappedManager.contains(aPrecondition);
		}
	
		public function accept(aPrecondition : EventDescriptor) : void 
		{
			mWrappedManager.accept(aPrecondition);
		}
		
		public function acceptEventSource(aEventSource : IEventDispatcher) : void 
		{
			mWrappedManager.acceptEventSource(aEventSource);
		}
	
		public function acceptAll() : void 
		{
			mWrappedManager.acceptAll();
		}
	
		public function ignore(aPrecondition : EventDescriptor) : void 
		{
			mWrappedManager.ignore(aPrecondition);
		}
		
		public function ignoreEventSource(aEventSource : IEventDispatcher) : void 
		{
			mWrappedManager.ignoreEventSource(aEventSource);
		}
	
		public function ignoreAll() : void 
		{
			mWrappedManager.ignoreAll();
		}
	
		public function reset() : void 
		{
			mWrappedManager.reset();
			mResetBeforeStart = false;
		}
	
		private function onPreconditionsMet(aEvent : PreconditionsManagerEvent) : void 
		{
			dispatchEvent(new TaskEvent(PreconditionsManagerEvent.PRECONDITIONS_MET));
			
			if(mIsRunning)
			{
				mIsRunning = false;
				mResetBeforeStart = true;
				dispatchEvent(new TaskEvent(TaskEvent.COMPLETED));
			}
		}
	}
}
